#ifndef  _Z9_SYNC_H
#define  _Z9_SYNC_H
#include <pthread.h>
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <sys/time.h>
#include <errno.h>
#include "util/z9_time.h"

typedef struct z9_mutex     z9_mutex;

typedef struct z9_condition z9_condition;

/*Mutex*/
struct z9_mutex {
	pthread_mutex_t     m_mutex;
	pthread_mutexattr_t m_attr;
};

/*Condition*/
struct z9_condition {
	pthread_cond_t cond;
	z9_mutex     *mtx;
};

static inline void z9_mutex_init(z9_mutex *m) {
	pthread_mutex_init(&m->m_mutex,NULL);
}

static inline void z9_mutex_uninit(z9_mutex *m) {
	pthread_mutex_destroy(&m->m_mutex);
}

static inline z9_mutex *z9_mutex_new() {
	z9_mutex *m = (z9_mutex*)malloc(sizeof(*m));
	if(!m) return NULL;
	z9_mutex_init(m);
	return m;
}

static inline void z9_mutex_del(z9_mutex *m) {
	z9_mutex_uninit(m);
	free(m);
}

static inline int32_t z9_mutex_lock(z9_mutex *m) {
	return pthread_mutex_lock(&m->m_mutex);
}

static inline int32_t z9_mutex_trylock(z9_mutex *m) {
	return pthread_mutex_trylock(&m->m_mutex);
}

static inline int32_t z9_mutex_unlock(z9_mutex *m) {
	return pthread_mutex_unlock(&m->m_mutex);
}

static inline void z9_condition_init(z9_condition *c,z9_mutex *mtx) {
	c->mtx = mtx;
	pthread_cond_init(&c->cond,NULL);
}

static inline void z9_condition_uninit(z9_condition *c) {
	pthread_cond_destroy(&c->cond);
}

static inline z9_condition *z9_condition_new(z9_mutex *mtx) {
	z9_condition *c = (z9_condition*)malloc(sizeof(*c));
	if(!c) return NULL;
	z9_condition_init(c,mtx);
	return c;
}

static inline void z9_condition_del(z9_condition *c) {
	z9_condition_uninit(c);
	free(c);
}


static inline int32_t z9_condition_wait(z9_condition *c) {
	return pthread_cond_wait(&c->cond,&c->mtx->m_mutex);
}

static inline int32_t z9_condition_timedwait(z9_condition *c,int32_t ms) {
	struct timespec ts;
	uint64_t msec;
	clock_gettime(CLOCK_REALTIME, &ts);
	msec = ms%1000;
	ts.tv_nsec += (msec*1000*1000);
	ts.tv_sec  += (ms/1000);
	if(ts.tv_nsec >= 1000*1000*1000) {
		ts.tv_sec += 1;
		ts.tv_nsec %= (1000*1000*1000);
	}
	return pthread_cond_timedwait(&c->cond,&c->mtx->m_mutex,&ts);
}

static inline int32_t z9_condition_signal(z9_condition *c) {
	return pthread_cond_signal(&c->cond);
}

static inline int32_t z9_condition_broadcast(z9_condition *c) {
	return pthread_cond_broadcast(&c->cond);
}

#endif
